//==========================================================================
// Copyright (c) 2000-2008,  Elastos, Inc.  All Rights Reserved.
//==========================================================================

#include <ddk.h>

class SleepSever : public CDeviceDriver
{
public:
    CARAPI Read(
        /* [in] */ UInt64 u64Offset,
        /* [in] */ UInt32 uNumberOfBytesToRead,
        /* [out] */ EzByteBuf ebbData,
        /* [out] */ IEvent * * ppCompletionEvent);

    CARAPI Write(
        /* [in] */ UInt64 u64Offset,
        /* [in] */ EzByteBuf ebbData,
        /* [out] */ UInt32 * puNumberOfBytesWritten,
        /* [out] */ IEvent * * ppCompletionEvent);

    CARAPI Control(
        /* [in] */ Int32 nControlCode,
        /* [in] */ EzByteBuf ebbInData,
        /* [out] */ EzByteBuf * pOutData,
        /* [out] */ IEvent * * ppCompletionEvent);

    virtual void Dispose() {}
};

EXTERN IDeviceDriver * CDECL CreateSleepServer0(uint_t uDeviceNo,
    void *pvParameter)
{
    SleepSever *pDriver = new SleepSever;
    if (NULL == pDriver) {
        kprintf("ERROR:There have no enough memory, %s, %d\n",
                        __FILE__, __LINE__);
        return NULL;
    }

    pDriver->AddRef();

    return pDriver;
}

ECode SleepSever::Read(
    /* [in] */ UInt64 u64Offset,
    /* [in] */ UInt32 uNumberOfBytesToRead,
    /* [out] */ EzByteBuf ebbData,
    /* [out] */ IEvent * * ppCompletionEvent)
{
    if (0 != u64Offset || NULL != ppCompletionEvent
        || !ebbData.IsNull() || 0 != uNumberOfBytesToRead) {
        return E_INVALID_ARGUMENT;
    }

    DzSleep();

    return NOERROR;
}

ECode SleepSever::Write(
    /* [in] */ UInt64 u64Offset,
    /* [in] */ EzByteBuf ebbData,
    /* [out] */ UInt32 * puNumberOfBytesWritten,
    /* [out] */ IEvent * * ppCompletionEvent)
{
    if (NULL != ppCompletionEvent || NULL != puNumberOfBytesWritten
        || !ebbData.IsNull()) {
        return E_INVALID_ARGUMENT;
    }

    SystemTime  currentTime;
    SystemTime  leastTime;
    UInt32  u32SleepTicks = (UInt32)u64Offset;
    ECode ec;

    DzGetSystemTime(&currentTime);
    leastTime.seconds = currentTime.seconds +
        DzTicksToMilliseconds(u32SleepTicks) / 1000;
    if (leastTime.seconds < currentTime.seconds) {
        leastTime.seconds = currentTime.seconds;
    }
    leastTime.microseconds = currentTime.microseconds +
        (DzTicksToMilliseconds(u32SleepTicks) % 1000) * 1000;
    if (leastTime.microseconds < currentTime.microseconds) {
        leastTime.microseconds = currentTime.microseconds;
    }

    ec = DzSleep(u32SleepTicks);

    if (S_TIMED_OUT == ec) {
        DzGetSystemTime(&currentTime);
        if (leastTime.seconds > currentTime.seconds) {
            ec = E_UNEXPECTED;
        }
        else if (leastTime.seconds == currentTime.seconds) {
            if (leastTime.microseconds > currentTime.microseconds) {
                ec = E_UNEXPECTED;
            }
        }
    }

    return ec;
}

ECode SleepSever::Control(
    /* [in] */ Int32 nControlCode,
    /* [in] */ EzByteBuf ebbInData,
    /* [out] */ EzByteBuf * pOutData,
    /* [out] */ IEvent * * ppCompletionEvent)
{
    if (ppCompletionEvent != NULL || !pOutData->IsNull()) {
        return E_INVALID_ARGUMENT;
    }

    ECode ec;

    switch (nControlCode) {
        case 0:
            return E_FAIL;
        case 1:
            if (!ebbInData.IsNull()) {
                return E_INVALID_ARGUMENT;
            }

            SystemTime  currentTime;
            UInt32  u32SleepTicks;
            SystemTime  leastTime;

            DzGetSystemTime(&currentTime);
            u32SleepTicks = currentTime.microseconds % 1024;

            leastTime.seconds = currentTime.seconds +
                DzTicksToMilliseconds(u32SleepTicks) / 1000;
            leastTime.microseconds = currentTime.microseconds +
                (DzTicksToMilliseconds(u32SleepTicks) % 1000) * 1000;

            ec = DzSleep(u32SleepTicks);

            if (S_TIMED_OUT == ec) {
                DzGetSystemTime(&currentTime);
                if (leastTime.seconds > currentTime.seconds) {
                    ec = E_FAIL;
                }
                else if (leastTime.seconds == currentTime.seconds) {
                    if (leastTime.microseconds > currentTime.microseconds) {
                        ec = E_FAIL;
                    }
                }
            }

            break;
        default:
            return E_NOT_IMPLEMENTED;
    }

    return ec;
}
